package com.troyhigh.njrotc.admintracker;

import java.util.ArrayList;
import java.util.Hashtable;
import java.sql.Date;
import java.io.*;

/**
 * A class that implements the Database interface in a way that uses TXT files to
 * store information. This is going to be more of a backup purpose'd file. This
 * backs up cadets to one file, and events to another file. Each roster is represented
 * by a different file in the /roster/ folder.
 * 
 * @author Quan Nguyen
 * @version 2008-December-23
 */
public class TXTDatabase implements Database
{
    private ArrayList<Cadet> cadets;
    private ArrayList<Event> events;
    
    private boolean connected = false;
    
    private boolean autocommit = false;
            
    private final String CADETS = "cadets";
    private final String EVENTS = "events";
    
    private final String EXTENSION = ".atd";
    private final String SEPARATOR = File.separator;
    private final String DIRECTORY = "library";
    
    private final String ROSTERDIR = "rosters";
    private final String ROSTEREXT = ".atr";
    
    private final String BACKUPDIR = "backup";
    
    public void connect()
    {
        System.out.println("Initiating file readers and reading...");
        loadCadets(CADETS);
        loadEvents(EVENTS);
    }
    
    private void loadCadets(String filename)
    {
        ArrayList<Cadet> c = new ArrayList<Cadet>();
        File name = new File(DIRECTORY + SEPARATOR + filename + EXTENSION);
        try
        {
            BufferedReader reader = new BufferedReader(new FileReader(name));
            String read = reader.readLine();
            if(read == null)
            {
                cadets = c;
                return;
            }
            do
            {
                String[] data = read.split(","); //We are counting that the data doesn't have commas.
                c.add(parseCadet(data));
                read = reader.readLine();
            } while (read != null);
            cadets = c;
        }
        catch(FileNotFoundException e)
        {
            System.out.println("File " + filename + " not found!");
        }
        catch(IOException e)
        {
            System.out.println("Error in reading cadets from the text file.");
        }
    }
    
    private Cadet parseCadet(String[] data)
    {
        if(data == null || data.length != 32)
            return null;
        try
        {
            int p = Integer.parseInt(data[0]);
            String l = data[1];
            String f = data[2];
            int i = Integer.parseInt(data[3]);
            char g = data[4].charAt(0);
            int r = Integer.parseInt(data[5]);
            int n = Integer.parseInt(data[6]);
            int[] a = new int[25];
            int[] s = new int[25];
            for(int k = 7; k < 32; k++)
            {
                a[k-7] = Integer.parseInt(data[k]);
            }
            for(int j = 32; j < 57; j++)
            {
                s[j-32] = Integer.parseInt(data[j]);
            }
            return new Cadet(p, l, f, i, g, r, n, a, s);
        }
        catch (Exception e)
        {
            System.out.println("Error in parsing cadet!");
        }
        return null;
    }
    
    private void loadEvents(String filename)
    {
        ArrayList<Event> e = new ArrayList<Event>();
        File name = new File(DIRECTORY + SEPARATOR + filename + EXTENSION);
        try
        {
            BufferedReader reader = new BufferedReader(new FileReader(name));
            String read = reader.readLine();
            if(read == null)
            {
                events = e;
                return;
            }
            do
            {
                String[] data = read.split(","); //We are counting that the data doesn't have commas.
                e.add(parseEvent(data));
                read = reader.readLine();
            } while (read != null);
            events = e;
        }
        catch(FileNotFoundException ex)
        {
            System.out.println("File " + filename + " not found!");
        }
        catch(IOException ex)
        {
            System.out.println("Error in reading cadets from the text file.");
        }
    }
    
    private Event parseEvent(String[] data)
    {
        if(data != null || data.length != 4)
            return null;
        try
        {
            String n = data[0];
            Date d = Date.valueOf(data[1]);
            Category c = Category.valueOf(data[2]);
            int r = Integer.parseInt(data[3]);
            Hashtable<Integer, Integer> t = parseRoster(AdminTracker.rosterID(n, d));
            return new Event(n, d, c, r, t);
        }
        catch(Exception ex)
        {
            System.out.println("Error in parsing event!");
        }
        return null;
    }
               
    //rid is the rosterID as produced by AdminTracker.
    private Hashtable<Integer, Integer> parseRoster(String rid)
    {
        File name = new File(DIRECTORY + SEPARATOR + ROSTERDIR + rid + ROSTEREXT);
        Hashtable<Integer, Integer> table = new Hashtable<Integer, Integer>();
        try
        {
            BufferedReader reader = new BufferedReader(new FileReader(name));
            String read = reader.readLine();
            if(read == null)
            {
                return table;
            }
            do
            {
                String[] entry = read.split(",");
                if(entry.length == 2)
                {
                    table.put(Integer.parseInt(entry[0]), Integer.parseInt(entry[1]));
                }
                read = reader.readLine();
            }
            while(read != null);
            return table;   
        }
        catch (Exception e)
        {
            System.out.println("Error in reading rosters!");
        }
        return new Hashtable<Integer, Integer>();
    }
                
    public boolean isConnected()
    {
        return connected;
    }
    
    public void commit()
    {
        System.out.println("Saving information...");
        saveCadets(CADETS);
        saveEvents(EVENTS, false);
    }
    
    private void saveCadets(String filename)
    {
        File name = new File(DIRECTORY + SEPARATOR + filename + EXTENSION);
        try
        {
            PrintStream writer = new PrintStream(new FileOutputStream(name));
            for(Cadet c : cadets)
            {
                String line = c.getPlatoon() + "," + c.getLastName() + "," +
                              c.getFirstName() + "," + c.getID() + "," +
                              c.getGender() + "," + c.getGrade() + "," +
                              c.getNSYear() + "," + c.ribbonValues() + "," +
                              c.semesterValues();
                writer.println(line);
            }
            writer.close();
        }
        catch (FileNotFoundException e)
        {
            System.out.println("File " + name + " not found!");
        }
    }
    
    private void saveEvents(String filename, boolean isBackingUp)
    {
        File name = new File(DIRECTORY + SEPARATOR + filename + EXTENSION);
        try
        {
            PrintStream writer = new PrintStream(new FileOutputStream(name));
            for(Event e : events)
            {
                String line = e.getName() + "," + e.getDate() + "," +
                              e.getCategory() + "," + e.getDuration() + ",";
                writer.println(line);
                saveRoster(e, isBackingUp);
            }
            writer.close();
        }
        catch(FileNotFoundException ex)
        {
            System.out.println("File " + name + " not found!");
        }
    }
    
    private void saveRoster(Event e, boolean isBackingUp)
    {
        String rid = e.getRosterID();
        File dir = new File(DIRECTORY + SEPARATOR + (isBackingUp ? BACKUPDIR  + SEPARATOR : "") + ROSTERDIR);
        dir.mkdir();
        File name = new File(dir, rid + ROSTEREXT);
        try
        {
            PrintStream writer = new PrintStream(new FileOutputStream(name));
            for(Integer i : e.getIDs())
            {
                String line = i + "," + e.get(i);
                writer.println(line);
            }
            writer.close();
        }
        catch(FileNotFoundException ex)
        {
            System.out.println("File " + name + " not found!");
        }
    }
    
    public void disconnect()
    {
        commit();
        System.out.println("Note: TXTDatabase does not require disconnection.");
    }
    
    public boolean canBackup()
    {
        return true;
    }
    
    public void backup()
    {
        System.out.println("Performing backup to text files.");
        System.out.println("Directory: " + (new File("")).getAbsolutePath());
        String longTime = "" + (new java.util.Date()).getTime();
        File direct = new File(DIRECTORY + SEPARATOR + BACKUPDIR + SEPARATOR + longTime);
        direct.mkdir();
        saveCadets(BACKUPDIR + SEPARATOR + longTime + SEPARATOR + CADETS);
        saveEvents(BACKUPDIR + SEPARATOR + longTime + SEPARATOR + EVENTS, true);
        System.out.println("Backup complete.");
    }
    
    public void restore(String filename)
    {
        try
        {
            String line = filename;
            if(line.matches("\\d*\\d"))
            {
                File directory = new File(BACKUPDIR + SEPARATOR + line);
                File cadetsFile = new File(directory, "cadets" + EXTENSION);
                File eventsFile = new File(directory, "events" + EXTENSION);
                if(cadetsFile.exists() && eventsFile.exists())
                {
                    loadCadets(cadetsFile.getName());
                    loadEvents(eventsFile.getName());
                    System.out.println("[restore] AdminTracker files restored.");
                }
                else
                {
                    System.out.println("[error] The backup directory is invalid.");
                }
            }
            else
            {
                System.out.println("[error] Not a valid backup directory.");
            }
            
        }
        catch(Exception e)
        {
            System.out.println("[error] Error in restoring from backup.");
        }
    }
    
    public boolean isAutoCommit() { return autocommit; }  
    public void setAutoCommit(boolean auto) { autocommit = auto; }
    
    public ArrayList<Cadet> getCadets() { return cadets; }
    public ArrayList<Event> getEvents() { return events; } 
    public void setCadets(ArrayList<Cadet> array)
    { 
        if(array != null) cadets = array; 
        if(autocommit)
        {
            System.out.println("Auto-committing...");
            commit();
        }
    } 
    public void setEvents(ArrayList<Event> array)
    { 
        if(array != null) events = array; 
        if(autocommit)
        {
            System.out.println("Auto-committing...");
            commit();
        }
    } 
}